/**
 * request 网络请求工具
 * 更详细的 api 文档: https://github.com/umijs/umi-request
 */
import umiRequest, { extend } from 'umi-request';
import { notification, message } from 'antd';
import { history } from 'umi';
import cookie from 'js-cookie';
import cloneDeep from 'lodash/cloneDeep';
import { loadingPub, ADD_GLOBAL_LOADING, REMOVE_GLOBAL_LOADING } from '@/hooks/useGlobalLoading';
import { clearLoginStates } from '@/utils/utils';
import { getLocale } from 'umi';
import { logRequest } from '../../config/config';

const userLanguage = getLocale();

// 不监控
// const excludePaths = ['/api/oa/v1/test/heartbeat', '/api/user/public/v1/account/login'];
// 不打印
const excludeLogPaths = [
    '/api/oa/v1/test/heartbeat',
    '/api/uc/public/v2new/account/login'
    // '/api/messagecenter/taskpool/v1/selfTaskCount', // 消息相关
    // '/api/messagecenter/taskpool/v1/self/task', // 消息相关
    // '/api/messagecenter/notice/v1/getNoticeList' // 消息相关
];

// const isProd = process.env.ENV === 'production';

const codeMessage = {
    200: '服务器成功返回请求的数据。',
    201: '新建或修改数据成功。',
    202: '一个请求已经进入后台排队（异步任务）。',
    204: '删除数据成功。',
    400: '发出的请求有错误，服务器没有进行新建或修改数据的操作。',
    401: '用户没有权限（令牌、用户名、密码错误）。',
    403: '用户得到授权，但是访问是被禁止的。',
    404: '发出的请求针对的是不存在的记录，服务器没有进行操作。',
    406: '请求的格式不可得。',
    408: '请求超时，请稍后重试',
    410: '请求的资源被永久删除，且不会再得到的。',
    422: '当创建一个对象时，发生一个验证错误。',
    500: '服务器发生错误，请检查服务器。',
    502: '网关错误。',
    503: '服务不可用，服务器暂时过载或维护。',
    504: '网关超时。'
};

// 根据语言添加相关权重映射
const languageMap = {
    zh: 'zh-CN,zh;q=0.9,en;q=0.8',
    'zh-cn': 'zh-CN,zh;q=0.9,en;q=0.8',
    en: 'en-US,en;q=0.9',
    'en-us': 'en-US,en;q=0.9'
};

/**
 * 异常处理程序
 */
// eslint-disable-next-line consistent-return
const errorHandler = error => {
    const { response = {} } = error;

    if (error?.message?.includes('timeout')) {
        return {
            data: {
                code: 408,
                msg: codeMessage[408] || error.message
            }
        };
    }

    if (umiRequest.isCancel(error)) {
        return {
            data: {
                code: 504,
                msg: error.message || codeMessage[504]
            }
        };
    }

    const errortext = codeMessage[response.status] || response.statusText;
    const { status, url } = response;
    if (status === 401) {
        clearLoginStates();
        const { pathname, search } = window.location;
        // 判断是否是外部招聘宣传页，跳转对应的登录界面
        if (pathname.startsWith('/recruitment')) {
            if (!search?.includes('redirect')) {
                if (!search?.includes('?')) {
                    history.push(`/recruitment/login?redirect=${pathname}`);
                } else {
                    history.push(`/recruitment/login${search}&redirect=${pathname}`);
                }
            } else {
                history.push(`/recruitment/login${search}`);
            }
        } else {
            history.push('/user/login');
        }

        return {
            data: {
                code: 401,
                msg: codeMessage[401] || error.message
            }
        };
    }
    // 这边添加这个为了，由于登出的时候，有时候接口会报500，导致下次登陆按钮失效。
    // 所以这边额外对这个进行了处理，看看会不会好点。
    if (status === 500) {
        return {
            data: {
                code: 500,
                msg: codeMessage[500] || error.message
            }
        };
    }
    if (process.env.NODE_ENV !== 'production') {
        notification.error({
            message: `请求错误 ${status}: ${url}`,
            description: errortext
        });
    }
};

/**
 * 配置request请求时的默认参数
 */
const request = extend({
    timeout: 20000,
    errorHandler, // 默认错误处理
    credentials: 'include' // 默认请求是否带上cookie
});

message.config({
    maxCount: 1
});

const cacheRequest = [];
let isTokenPending = false; // 用来控制token刷新中状态

// request拦截器
request.interceptors.request.use((url, options) => {
    const { isFile = false, data = {}, headers, ...rest } = options;
    loadingPub(ADD_GLOBAL_LOADING, { url, data });
    const getRequestData = () => {
        let requestData;
        if (isFile) {
            requestData = JSON.stringify(data);
        } else {
            requestData = data;
        }
        return requestData;
    };

    if (logRequest) {
        if (!excludeLogPaths.includes(url)) {
            console.info(
                `%c 请求路径：${url}，请求类型：${(options.method || 'GET').toUpperCase()}，请求参数：`,
                'color: #ff6600',
                options.data || options.params
            );
        }
        const newUser = localStorage.getItem('user') ? JSON.parse(localStorage.getItem('user')) : {};
        // isFile 如果请求的是文件流 服务端要求body不包裹在params里😠
        const tmpOptions = {
            data: getRequestData(),
            interceptors: true,
            headers: {
                ...headers,
                Authorization: cookie.get('Authorization'),
                uc: newUser.userCode || '',
                'Accept-Language': languageMap[userLanguage?.toLowerCase()]
            },
            ...rest
        };

        const { expTime, token: userToken, refreshToken } = JSON.parse(localStorage.getItem('loginInfo') || '{}');

        if (userToken) {
            // 如果有token 就走token逻辑

            // 如果是刷新token接口，就直接过，不要拦截它
            if (url === '/api/uc/public/v2/account/token') {
                return {
                    url,
                    options: tmpOptions
                };
            }
            const nowTime = new Date().getTime();

            if (expTime && nowTime >= expTime) {
                // 只是过期了，那就去拿新的token
                if (isTokenPending) {
                    // 如果正在发送中，此请求就等一会吧，生成一个Promise 等新token返回的时候，再resolve
                } else {
                    // 如果没发送，立刻改为发送状态
                    isTokenPending = true;
                    request('/api/uc/public/v2/account/token', {
                        method: 'POST',
                        data: {
                            refresh_token: refreshToken,
                            client_id: '1422402458692440065',
                            client_secret: '899730c05b2562b3f2e7fd2b400dfd06',
                            grant_type: 'refresh_token'
                        }
                    })
                        .then(res => {
                            if (res.code === 10000) {
                                // 更新token和loginInfo
                                cookie.set('Authorization', res?.data?.token || '', {
                                    expires: 30
                                });
                                localStorage.setItem(
                                    'loginInfo',
                                    JSON.stringify({
                                        ...JSON.parse(localStorage.getItem('loginInfo') || '{}'),
                                        ...res?.data,
                                        expTime: new Date().getTime() + res?.data?.expiresIn * 1000
                                    })
                                );
                                cacheRequest.map(cb => cb());
                            }
                        })
                        .finally(() => {
                            isTokenPending = false;
                        });
                }

                return new Promise(resolve => {
                    cacheRequest.push(() => {
                        resolve();
                    });
                });
            }
        }

        return {
            url,
            options: tmpOptions
        };
    }
    return null;
});

// 第二个拦截器，第一个拦截器有可能返回Promise,那么Promise由第二个拦截器处理
request.interceptors.request.use(async (url, options) => {
    const { isFile = false, data = {}, headers, ...rest } = options;
    const getRequestData = () => {
        let requestData;
        if (isFile) {
            requestData = JSON.stringify(data);
        } else {
            requestData = data;
        }
        return requestData;
    };

    const { token: userToken, userCode } = JSON.parse(localStorage.getItem('loginInfo') || '{}');
    const tmpOptions = {
        data: getRequestData(),
        interceptors: true,
        headers: {
            ...headers,
            Authorization: userToken,
            uc: userCode || '',
            'Accept-Language': languageMap[userLanguage?.toLowerCase()]
        },
        ...rest
    };

    return {
        url,
        options: tmpOptions
    };
});

// response拦截器, 处理response
request.interceptors.response.use(async response => response);

// 数据中的null -> undefined
const ergodic = obj => {
    const cloneObj = cloneDeep(obj);
    const fn = o => {
        if (o instanceof Object) {
            const ary = Array.isArray(o) ? o : Object.keys(o);
            ary.forEach((it, index) => {
                const key = Array.isArray(o) ? index : it;
                if (o[key] === null) {
                    // eslint-disable-next-line no-param-reassign
                    o[key] = undefined;
                } else if (o[key] instanceof Object) {
                    fn(o[key]);
                }
            });
        }
    };
    fn(cloneObj);
    return cloneObj;
};

async function requestWrap(...params) {
    const pa = {
        ...params[1],
        getResponse: true
    };
    const result = await request(params[0], pa);

    loadingPub(REMOVE_GLOBAL_LOADING, { url: params[0], data: params[1] });

    // 截取 20008 状态码
    // if (result && result.data && result.data.code === 20008) {
    //     clearLoginStates();
    //     message.error(result.data.msg);
    //     history.push('/user/login');
    // }

    // 截取 30012 状态码
    if (result && result.data && result.data.code === 30012) {
        message.error(result.data.msg);
        history.push({ pathname: '/personal/portal', state: { tabRoute: true } });
    }

    // 截取 20008 状态码，处理权限不足
    if (result && result.data && result.data.code === 20008) {
        message.error(result.data.msg);
        history.push('/exception/403');
    }
    // 非正常返回，console一下
    // 20012/20013 属于首次登陆的判断码，不打印
    if (
        result &&
        result.data &&
        result.data.code !== 10000 &&
        result.data.code !== 20012 &&
        result.data.code !== 20013
    ) {
        console.error(params[0], result);
    }

    const getResponse = params[1] && params[1].getResponse;
    const encryption = params[1] && params[1].encryption;
    const resultData = result && result.data && result.data.data;

    if (getResponse && encryption === false) {
        if (logRequest && !excludeLogPaths.includes(params[0])) {
            console.info(`%c 请求路径：${params[0]}，返回数据：`, 'color: green', result);
        }
        return Promise.resolve({
            ...result
        });
    }
    // 解密+处理null
    // const responseData = ergodic(encryptUtil.decrypt(resultData, secret));
    const responseData = ergodic(resultData);

    if (logRequest && !excludeLogPaths.includes(params[0])) {
        console.info(`%c 请求路径：${params[0]}，返回数据：`, 'color: green', responseData);
    }
    if (getResponse) {
        return Promise.resolve({
            ...result,
            data: {
                ...result.data,
                data: cloneDeep(responseData)
            }
        });
    }
    return Promise.resolve({
        ...(result && result.data),
        data: cloneDeep(responseData)
    });
}
Object.keys(request).forEach(key => {
    requestWrap[key] = request[key];
});

/**
 * 过滤请求参数, 去掉空值/null/undefined
 * @param params
 * @returns params
 */
export function filterUsefulRequestParams(params) {
    const result = {};
    if (!params) {
        return null;
    }
    Object.entries(params).forEach(([key, value]) => {
        if (value !== '' && value !== undefined && value !== null) {
            // 是否要判断空数组?  !(value instanceof Array && value.length === 0)
            result[key] = value;
        }
    });
    return result;
}

export default requestWrap;

/**
 * 判断响应是否成功
 * @param responseOrCode 调用服务的返回对象或返回的编码
 * @returns {boolean} 返回是否成功
 */
const isSuccess = responseOrCode => responseOrCode === 10000 || responseOrCode?.code === 10000;
export { isSuccess };
